﻿using System;
using System.IO;
using System.Net;
using System.Xml;
using System.Linq;
using System.Text;
using System.Activities;
using System.Activities.Expressions;
using System.Activities.Presentation.PropertyEditing;
using System.Activities.Statements;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Markup;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Data.SqlTypes;

namespace Vision.Core.ActivityComponents.Sql
{
    /// <summary>
    /// 
    /// </summary>
    [ContentProperty("Body")]
    [Designer(typeof(SqlExecuteDataSetDesigner))]
    public class SqlExecuteDataSet : NativeActivity
    {
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false)]
        [DefaultValue(null)]
        public ActivityAction<DataSet> Body { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [Category("Input")]
        [RequiredArgument]
        [DefaultValue(null)]
        public InArgument<System.Data.SqlClient.SqlConnection> SqlConn { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [Category("Input")]
        [RequiredArgument]
        [DefaultValue("")]
        public InArgument<string> SqlCmdText { get; set; }
        
        /// <summary>
        /// 
        /// </summary>
        [Category("Input")]
        [RequiredArgument]
        [DefaultValue(30)]
        public InArgument<int> SqlCmdTimeout { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [Category("Input")]
        [DefaultValue(null)]
        public InArgument<Dictionary<string, object>> SqlParameters { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [Category("Output")]
        [DefaultValue(null)]
        public OutArgument<DataSet> DataSet { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [Category("Input")]
        [DefaultValue(null)]
        public CmdType SqlCmdType { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public SqlExecuteDataSet() : base()
        {
            this.Body = new ActivityAction<DataSet>(){
                Argument = new DelegateInArgument<DataSet>() { Name = "dataSet" }
            };

            this.SqlCmdTimeout = 30;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="metadata"></param>
        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
            RuntimeArgument sqlConnectionArgument = new RuntimeArgument("SqlConn", typeof(System.Data.SqlClient.SqlConnection), ArgumentDirection.In, true);
            metadata.Bind(this.SqlConn, sqlConnectionArgument);
            metadata.AddArgument(sqlConnectionArgument);

            RuntimeArgument sqlCmdTextArgument = new RuntimeArgument("SqlCmdText", typeof(string), ArgumentDirection.In, true);
            metadata.Bind(this.SqlCmdText, sqlCmdTextArgument);
            metadata.AddArgument(sqlCmdTextArgument);

            RuntimeArgument sqlCmdTimeoutArgument = new RuntimeArgument("SqlCmdTimeout", typeof(int), ArgumentDirection.In, true);
            metadata.Bind(this.SqlCmdTimeout, sqlCmdTimeoutArgument);
            metadata.AddArgument(sqlCmdTimeoutArgument);

            RuntimeArgument sqlParametersArgument = new RuntimeArgument("SqlParameters", typeof(Dictionary<string, object>), ArgumentDirection.In, false);
            metadata.Bind(this.SqlParameters, sqlParametersArgument);
            metadata.AddArgument(sqlParametersArgument);

            RuntimeArgument dataSetArgument = new RuntimeArgument("DataSet", typeof(DataSet), ArgumentDirection.Out, false);
            metadata.Bind(this.DataSet, dataSetArgument);
            metadata.AddArgument(dataSetArgument);

            metadata.AddDelegate(this.Body);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        protected override void Execute(NativeActivityContext context)
        {
            var paramList = this.SqlParameters.Get(context);
            var dataSet = new DataSet();
                                    
            using (SqlCommand sqlCmd = new SqlCommand()){
                sqlCmd.Connection = this.SqlConn.Get(context);
                sqlCmd.CommandText = this.SqlCmdText.Get(context);
                sqlCmd.CommandType = this.GetSqlCommandTypeFromCmdType(this.SqlCmdType);
                sqlCmd.CommandTimeout = this.SqlCmdTimeout.Get(context);
                if (paramList != null)
                {
                    foreach (string param in paramList.Keys)
                    {
                        sqlCmd.Parameters.Add(new SqlParameter(param, paramList[param]));
                    }
                }

                using (SqlDataAdapter sqlAdapter = new SqlDataAdapter(sqlCmd)){
                    sqlAdapter.Fill(dataSet);    
                } 
            }

            if (this.DataSet != null){
                this.DataSet.Set(context, dataSet);
            }

            if (this.Body != null && this.Body.Handler != null){
                context.ScheduleAction(this.Body, dataSet);
            }                                
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cmdType"></param>
        /// <returns></returns>
        private System.Data.CommandType GetSqlCommandTypeFromCmdType(CmdType cmdType)
        {
            switch (cmdType)
            {
                case CmdType.StoredProcedure:
                    return System.Data.CommandType.StoredProcedure;
                case CmdType.Text:
                    return System.Data.CommandType.Text;
                default:
                    return System.Data.CommandType.Text;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public enum CmdType
        {
            StoredProcedure,
            Text
        }
    }
}
